package com.linkgie.galaxyframework.process;

import java.util.List;
import java.util.Properties;
import java.util.Set;

/**
 * 流程定义编辑器；
 * <p>
 * 
 * @author Hike
 *
 */
public interface ProcessDefinitionEditor {

	/**
	 * 流程定义的Id；
	 * 
	 * @param id
	 * @return
	 */
	ProcessDefinitionEditor setId(String id);

	/**
	 * 设置流程的名称；
	 * 
	 * @param name
	 * @return
	 */
	ProcessDefinitionEditor setName(String name);

	/**
	 * 设置默认的条件验证器；
	 * <p>
	 * 
	 * @param <T>
	 * @param conditionValidatorType
	 * @return
	 */
	default <T extends ConditionValidator> ProcessDefinitionEditor setConditionValidator(Class<T> conditionValidatorType) {
		return setConditionValidator(conditionValidatorType.getName());
	}

	/**
	 * 设置默认的条件验证器；
	 * <p>
	 * 
	 * @param <T>
	 * @param conditionValidatorType
	 * @return
	 */
	<T extends ConditionValidator> ProcessDefinitionEditor setConditionValidator(String conditionValidatorType);

	/**
	 * 设置默认的流程节点跳转预处理器；
	 * 
	 * @param <T>
	 * @param nodeTransferedPrehandlerType
	 * @return
	 */
	default <T extends NodeTransferedPrehandler> ProcessDefinitionEditor setNodeTransferedPrehandler(Class<T> nodeTransferedPrehandlerType) {
		return setNodeTransferedPrehandler(nodeTransferedPrehandlerType.getName());
	}

	/**
	 * 设置默认的流程节点跳转预处理器；
	 * 
	 * @param <T>
	 * @param nodeTransferedPrehandlerType
	 * @return
	 */
	<T extends NodeTransferedPrehandler> ProcessDefinitionEditor setNodeTransferedPrehandler(String nodeTransferedPrehandlerType);
	
	/**
	 * 设置默认的流程结束处理器；
	 * 
	 * @param <T>
	 * @param processCompletedHandlerType
	 * @return
	 */
	default <T extends ProcessCompletedHandler> ProcessDefinitionEditor setProcessCompletedHandler(Class<T> processCompletedHandlerType) {
		return setProcessCompletedHandler(processCompletedHandlerType.getName());
	}
	
	/**
	 * 设置默认的流程结束处理器；
	 * 
	 * @param <T>
	 * @param processCompletedHandlerType
	 * @return
	 */
	<T extends ProcessCompletedHandler> ProcessDefinitionEditor setProcessCompletedHandler(String processCompletedHandlerType);


	/**
	 * 流程启动设置；
	 * 
	 * @return
	 */
	StartingConfigurer start();

	/**
	 * 流程终止设置；
	 * 
	 * @return
	 */
	TerminationTransferConfigurer terminate();

	/**
	 * 流程执行设置；
	 * 
	 * @param nodeId
	 * @return
	 */
	ExecutionNodeConfigurer execute(String nodeId);

	/**
	 * 流程退出设置；
	 * 
	 * @param nodeId
	 * @return
	 */
	EndNodeConfigurer exit(String nodeId);

	/**
	 * 选择多个执行节点执行设置；
	 * <p>
	 * 
	 * 如果节点不存在，则会自动创建节点；
	 * 
	 * @return
	 */
	MultiNodesConfigurer selectNodes(String... nodeIds);

	/**
	 * 选择所有对执行节点执行设置；
	 * 
	 * @return
	 */
	MultiNodesConfigurer selectAllNodes();

	/**
	 * 生成流程定义；
	 * 
	 * @return
	 */
	ProcessDefinition build();

	/**
	 * 流程的启动设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface StartingConfigurer extends AttributesConfigurer<StartingConfigurer>, ProcessConfigurer {

		/**
		 * 定义流程的入口节点（即首个执行节点）；
		 * 
		 * @return
		 */
		default ExecutionNodeConfigurer begin() {
			return begin(null);
		}

		/**
		 * 定义流程的入口节点（即首个执行节点）；
		 * 
		 * @return
		 */
		ExecutionNodeConfigurer begin(String nodeId);

	}

	/**
	 * 流程执行节点设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface ExecutionNodeConfigurer extends NodeConfigurer<ExecutionNodeConfigurer> {

		/**
		 * 设置节点类型；
		 * 
		 * @param handler
		 * @return
		 */
		ExecutionNodeConfigurer setType(String type);

		/**
		 * 设置节点的条件验证器；
		 * <p>
		 * 非必须选项，如果未设置，则采用流程默认的设置；
		 * 
		 * @param <T>
		 * @param validatorType
		 * @return
		 */
		<T extends ConditionValidator> ExecutionNodeConfigurer setConditionValidator(Class<T> validatorType);

		/**
		 * 设置节点预执行处理器；
		 * 
		 * @param <T>
		 * @param nodePrehandlerType
		 * @return
		 */
		<T extends NodeTransferedPrehandler> ExecutionNodeConfigurer setNodePrehandler(Class<T> nodePrehandlerType);

		/**
		 * 设置条件分支；
		 * <p>
		 * 
		 * 条件分支不是必须的；
		 * 
		 * @param condition
		 * @return
		 */
		ConditionalTransferConfigurer inCaseOf(String condition);

		/**
		 * 设置默认分支；
		 * <p>
		 * 
		 * 默认分支是必须的；
		 * 
		 * @return
		 */
		DirectBranchConfigurer byDefault();

		/**
		 * 指定 Id 的条件分支；如果未设置条件分支，则返回 null；
		 * 
		 * @param branchId
		 * @return
		 */
		ConditionalTransferConfigurer condition(String branchId);

		/**
		 * 当前节点的所有条件分支；
		 * 
		 * @return
		 */
		List<ConditionalTransferConfigurer> conditions();

	}

	/**
	 * 流程执行节点设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface EndNodeConfigurer
			extends NodeConfigurer<EndNodeConfigurer>, ExitConfigurer<EndNodeConfigurer> {

	}

	/**
	 * 流程的条件跳转设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface ConditionalTransferConfigurer
			extends BranchTransferConfigurer<ConditionalTransferConfigurer>,
			NamableElementConfigurer<ConditionalTransferConfigurer> {

		/**
		 * 设置条件的计算次序；
		 * <p>
		 * 
		 * 这不是必须的设置；<br>
		 * 
		 * 默认情况下会按照在源节点上定义条件的先后次序设置默认的 order （通过
		 * （{@link ExecutionNodeConfigurer#inCaseOf(String)}）方法设置）；
		 * 
		 * @param order
		 * @return
		 */
		ConditionalTransferConfigurer order(int order);

	}

	/**
	 * 流程执行节点设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface DirectBranchConfigurer extends BranchTransferConfigurer<DirectBranchConfigurer> {

	}

	/**
	 * 流程的分支跳转基本设置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface TerminationTransferConfigurer extends AttributesConfigurer<TerminationTransferConfigurer>,
			TransferConfigurer<ExecutionNodeConfigurer, EndNodeConfigurer> {

	}

	/**
	 * 多节点设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface MultiNodesConfigurer extends ProcessConfigurer {

		/**
		 * 节点 Id 列表；
		 * 
		 * @return
		 */
		Set<String> nodeIds();

		/**
		 * 多节点对默认分支；
		 * 
		 * @return
		 */
		MultiNodesTransferConfigurer inDefault();

	}

	/**
	 * 多节点设置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface MultiNodesTransferConfigurer extends NamableElementConfigurer<MultiNodesTransferConfigurer>,
			AttributesConfigurer<MultiNodesTransferConfigurer>,
			TransferConfigurer<MultiNodesTransferConfigurer, MultiNodesExitConfigurer> {

		/**
		 * 应用对多节点对设置；
		 * 
		 * @return
		 */
		MultiNodesConfigurer apply();

	}

	public static interface MultiNodesExitConfigurer extends ExitConfigurer<MultiNodesExitConfigurer> {

		MultiNodesTransferConfigurer sources();

	}

	/**
	 * 流程节点的基本设置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface NodeConfigurer<T>
			extends NamableElementConfigurer<T>, AttributesConfigurer<T>, ProcessConfigurer {

	}

	/**
	 * 流程的分支跳转基本设置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface BranchTransferConfigurer<T> extends NamableElementConfigurer<T>, AttributesConfigurer<T>,
			TransferConfigurer<ExecutionNodeConfigurer, EndNodeConfigurer> {

		/**
		 * 返回与当前条件分支关联的源节点关联的节点配置；
		 * 
		 * @return
		 */
		ExecutionNodeConfigurer source();

	}

	/**
	 * 流程元素的基本设置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface NamableElementConfigurer<T> {

		/**
		 * 当前设置的名称；
		 * 
		 * @return
		 */
		String getName();

		/**
		 * 设置名称；
		 * 
		 * @param name 名称；
		 * @return
		 */
		T setName(String name);
	}

	/**
	 * 流程配置；
	 * 
	 * @author Hike
	 *
	 */
	public static interface ProcessConfigurer {
		/**
		 * 返回到流程层面的定义；
		 * 
		 * @return
		 */
		ProcessDefinitionEditor process();
	}

	/**
	 * 流程跳转配置；
	 * 
	 * @author Hike
	 *
	 * @param <T> 跳转目标的配置类型；
	 * @param <E> 退出目标的配置类型；
	 */
	public static interface TransferConfigurer<T, E> {

		/**
		 * 满足条件则跳转到指定的节点；
		 * 
		 * <p>
		 * 
		 * 此方法表示的跳转操作和退出操作（{@link #exit(String)}）是互斥的，设置其中一项会冲掉另一项的设置；
		 * 
		 * @param nodeId 要跳转的节点Id；<br>
		 *               如果指定的节点不存在，则创建一个；<br>
		 *               如果节点已经存在，则关联到该节点已有的配置，同时放弃对原引用的节点的依赖；
		 * @return 与跳转的目标节点关联的节点配置；
		 * 
		 */
		T jumpTo(String nodeId);

		/**
		 * 满足条件则跳转到指定的退出节点；
		 * <p>
		 * 跳转和退出是互斥的，配置退出时则清除跳转设置；
		 * 
		 * @param nodeId 退出节点的Id；<br>
		 *               如果指定的节点不存在，则创建一个；<br>
		 *               如果节点已经存在，则关联到该节点已有的配置，同时放弃对原引用的节点的依赖；
		 * @return
		 */
		E exit(String nodeId);
	}

	/**
	 * 退出设置；
	 * 
	 * @author Hike
	 *
	 * @param <T> 连续设置的配置类型；
	 */
	public static interface ExitConfigurer<T> {

		T code(long code);

		T message(String message);
	}

	/**
	 * 属性配置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface AttributesConfigurer<T> {

		/**
		 * 设置属性；
		 * 
		 * @param name  属性名；
		 * @param value 属性值；
		 * @return
		 */
		T setAttribute(String name, String value);

		/**
		 * 设置属性；
		 * 
		 * @param attributes
		 * @return
		 */
		T setAttributes(Properties attributes);
	}

	/**
	 * Id配置；
	 * 
	 * @author Hike
	 *
	 * @param <T>
	 */
	public static interface IdConfigurer<T> {

		/**
		 * 设置 Id；
		 * <p>
		 * 
		 * @param id 在所属的流程定义中唯一的 id；
		 * @return
		 */
		T setId(String id);
	}

}
